//
//  Protocol.swift
//  KPBaseProject
//
//  Created by Kipp Dev on 2018/3/20.
//  Copyright © 2018年 Kipp. All rights reserved.
//

// swiftlint:disable cyclomatic_complexity

import Foundation
import RxAlamofire
import Alamofire
import HandyJSON
import RxSwift
import RxCocoa
import SwiftyJSON
import SwifterSwift

let resultCode = "resultState"
let resultMessage = "msg"
let resultData = "data"

enum RequestStatus: Int {
    case requestSuccess = 200
    case requestErrorNoParameters = 400
    case requestError
}

enum KPError: Swift.Error {
    // 解析失败
    case parseJSONError(Any)
    //参数未传
    case noParameterError(Any)
    // 网络请求发生错误
    case requestFailed(Int?)
    // 接收到的返回没有data
    case noResponse
    //服务器返回了一个错误代码
    case unexpectedResult(resultCode: String?, resultMsg: String?)
    //其他错误
    case otherError(Any)
    //系统错误
    case systemError(Any)

    func debug() -> KPError {
        switch self {
        case .parseJSONError(let data):
            KPLog(data)
        case .noParameterError(let data):
            KPLog(data)
        case .requestFailed(let data):
            KPLog("statusCode:\(data.or(0))")
        case .noResponse:
            KPLog("网络请求没有返回数据！")
        case .unexpectedResult(let resultCode, let resultMsg):
            KPLog("resultCode:\(resultCode.or("--")),resultMsg:\(resultMsg.or("--"))")
        case .otherError(let data):
            KPLog(data)
        case .systemError(let data):
            KPLog(data)
        }
        return self
    }

}

public struct KPBaseModel<T: HandyJSON>: HandyJSON {
    var resultState: Int = 0
    var msg: String = ""
    var data: T?
    public init() { }
}

public struct KPBaseArrayModel<T: HandyJSON>: HandyJSON {
    var resultState: Int = 0
    var msg: String = ""
    var data: [T?]?
    public init() { }
}

public struct KPBaseJSONModel: HandyJSON {
    var resultState: Int = 0
    var msg: String = ""
    var data: JSON?
    public init() { }
    public mutating func mapping(mapper: HelpingMapper) {
        mapper <<<
        self.data <-- TransformOf<JSON,Any>.init(fromJSON: { (any) -> JSON in
            return JSON.init(any!)
        }, toJSON: {_ in
            return nil
        })
    }
}

public extension Observable {

    ///通用数据解析方法
    ///
    /// - Returns: 返回一个原始JSON数据的模型
    func mapBaseModel() -> Observable<KPBaseJSONModel> {
        return map { response in
            guard let response = response as? (HTTPURLResponse, Any) else {
                throw KPError.noResponse.debug()
            }

            guard (200...209) ~= response.0.statusCode else {
                throw KPError.requestFailed(response.0.statusCode).debug()
            }

            guard let jsonData = response.1 as? [String: Any] else {
                throw KPError.parseJSONError(response.1).debug()
            }

            guard let resultState = jsonData[resultCode] as? String else {
                throw KPError.parseJSONError(jsonData).debug()
            }

            // MARK: - -1：系统错误，0：参数未传，1：请求成功，2：其他错误
            switch resultState {
            case "0":
                throw KPError.noParameterError(jsonData).debug()
            case "1":
                guard let object = JSONDeserializer<KPBaseJSONModel>.deserializeFrom(dict: jsonData) else {
                    throw KPError.parseJSONError(jsonData).debug()
                }
                return object
            case "2":
                throw KPError.otherError(jsonData).debug()

            default:
                throw KPError.systemError(jsonData).debug()
            }

        }
    }

    /// 解析单个模型
    ///
    /// - Parameter type: 固定模型中 data 里面值对应的模型结构体
    /// - Returns: 包含所传对应模型的基础模型序列
    func mapObject<T:HandyJSON>(_ type: T.Type) -> Observable<KPBaseModel<T>> {

        return map { response in

            guard let response = response as? (HTTPURLResponse, Any) else {
                throw KPError.noResponse.debug()
            }

            guard (200...209) ~= response.0.statusCode else {
                throw KPError.requestFailed(response.0.statusCode).debug()
            }

            guard let jsonData = response.1 as? [String: Any] else {
                throw KPError.parseJSONError(response.1).debug()
            }

            guard let resultState = jsonData[resultCode] as? String else {
                throw KPError.parseJSONError(jsonData).debug()
            }

            // MARK: - -1：系统错误，0：参数未传，1：请求成功，2：其他错误
            switch resultState {
            case "0":
                throw KPError.noParameterError(jsonData).debug()
            case "1":
                guard let object = JSONDeserializer<KPBaseModel<T>>.deserializeFrom(dict: jsonData) else {
                    throw KPError.parseJSONError(jsonData).debug()
                }
                return object
            case "2":
                throw KPError.otherError(jsonData).debug()

            default:
                throw KPError.systemError(jsonData).debug()
            }
        }
    }

    /// 解析包含指定对象的模型数组
    ///
    /// - Parameter type: 固定模型中 data 里面值对应的模型结构体数组
    /// - Returns: 包含所传对应模型的基础模型序列
    func mapArray<T:HandyJSON>(_ type: T.Type) -> Observable<KPBaseArrayModel<T>> {
        return map { response in

            guard let response = response as? (HTTPURLResponse, Any) else {
                throw KPError.noResponse.debug()
            }

            guard (200...209) ~= response.0.statusCode else {
                throw KPError.requestFailed(response.0.statusCode).debug()
            }

            guard let jsonData = response.1 as? [String: Any] else {
                throw KPError.parseJSONError(response.1).debug()
            }

            guard let resultState = jsonData[resultCode] as? Int else {
                throw KPError.parseJSONError(jsonData).debug()
            }

            // MARK: - -1：系统错误，0：参数未传，1：请求成功，2：其他错误
            switch resultState {
            case 0:
                throw KPError.noParameterError(jsonData).debug()
            case 1:
                var model = KPBaseArrayModel<T>()

                if let resultState = jsonData[resultCode] as? Int {
                    model.resultState = resultState
                }

                if let msg = jsonData[resultMessage] as? String {
                    model.msg = msg
                }

                guard let jsonArray = jsonData[resultData] as? [Any], let models = JSONDeserializer<T>.deserializeModelArrayFrom(array: jsonArray) else {
                    throw KPError.parseJSONError(jsonData).debug()
                }

                model.data = models
                return model

            case 2:
                throw KPError.otherError(jsonData).debug()

            default:
                throw KPError.systemError(jsonData).debug()
            }
        }
    }
}
